﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Web.Ajax.Data;

namespace Web.Ajax.InversionOfControl
{
	public class Container : IContainer
	{
		private readonly Dictionary<Type, Type> map;

		public static readonly IContainer Instance = new Container();

		private Container()
		{
			map = new Dictionary<Type, Type>();
		}

		public void Map<IT, T>() where T : IT
		{
			map.Add(typeof(IT), typeof(T));
		}
		
		public object GetImplementation(Type t)
		{
			if (t == null)
				return null;

			if(!map.Keys.Contains(t))
				throw new Exception("No Inversion of Control mapping for this Type: " + t.Name);

			var implementationType = map[t];

			var defaultConstructor = implementationType.GetConstructor(Type.EmptyTypes);
			if(defaultConstructor!=null)
				return Activator.CreateInstance(implementationType);

			var constructorParameters = new List<object>();

			var c = implementationType.GetConstructors().FirstOrDefault();

			if (c == null)
				throw new Exception("No public constructor found for this Type: " + t.Name);

			var pl=c.GetParameters();
			pl.Each(p => {
				if (!p.ParameterType.IsInterface)
					throw new Exception("Constructor has a non-interface parameter.");
				constructorParameters.Add(GetImplementation(p.ParameterType));
			});

			return Activator.CreateInstance(implementationType, constructorParameters.ToArray());
		}

		public I GetImplementation<I>()
		{
			return (I)GetImplementation(typeof(I));
		}
	}
}
